package repo

import (
	"fmt"
	"server/common/dto/response"
	"server/core"
	"server/global"
	"strings"

	"gorm.io/gorm"
)

func (r *Repository[T]) CheckDataExistsByCondition(condition any, flag string) (bool, *response.ServiceError) {
	if flag == "" {
		flag = "AND"
	}
	var dynamicConditions []string
	var args []any

	if m, ok := condition.(map[string]any); ok {
		for key, value := range m {
			conditionStr := fmt.Sprintf("%s = ?", key)
			dynamicConditions = append(dynamicConditions, conditionStr)
			args = append(args, value)
		}
	}

	fixedCondition := "is_delete = false AND"
	dynamicQuery := strings.Join(dynamicConditions, " "+flag+" ")
	query := fixedCondition + " " + dynamicQuery

	var count int64
	result := r.DB.Model(new(T)).Where(query, args...).Count(&count)
	return count > 0, core.HandelError(result)
}

func (r *Repository[T]) CheckDataBatchExistsByIds(ids []string) (map[string]bool, *response.ServiceError) {
	var entities []T
	result := r.DB.Where("id IN ? ", ids).Find(&entities)
	if err := core.HandelError(result); err != nil {
		return nil, err
	}
	var existsMap = make(map[string]bool)
	for _, entity := range entities {
		if model, ok := any(&entity).(interface{ GetID() string }); ok {
			existsMap[model.GetID()] = true
		} else {
			return nil, response.WrapError(
				response.FailedCode,
				response.GetStatusCode(response.FailedCode).Message,
			)
		}
	}
	return existsMap, nil
}

func BuildQueryCondition(args ...interface{}) map[string]interface{} {
	result := make(map[string]interface{})
	switch len(args) {
	case 1:
		if m, ok := args[0].(map[string]interface{}); ok {
			return m
		}
	case 2:
		if key, ok := args[0].(string); ok {
			result[key] = args[1]
			return result
		}
	default:
		return nil
	}
	global.GA_LOGGER.Sugar().Panicf("构造请求参数发生错误")
	return nil
}

func UseTransactionWith(db *gorm.DB, fn func(tx *gorm.DB) *response.ServiceError) *response.ServiceError {
	tx := db.Begin()
	if tx.Error != nil {
		return response.WrapError(response.FailedCode, response.GetStatusCode(response.FailedCode).Message)
	}
	defer func() {
		if r := recover(); r != nil {
			tx.Rollback()
			panic(r)
		}
	}()
	if err := fn(tx); err != nil {
		tx.Rollback()
		return response.WrapError(err.Code, err.Err.Error())
	}
	if err := tx.Commit().Error; err != nil {
		tx.Rollback()
		return response.WrapError(response.FailedCode, response.GetStatusCode(response.FailedCode).Message)
	}
	return nil
}
